package club.emergency.wechat.wechat_api.provider.impl;

import club.emergency.wecaht.wechat_api.WechatApi;
import club.emergency.wechat.common.https.HttpsPostRequestUtil;
import club.emergency.wechat.common.response.ResponseEntity;
import club.emergency.wechat.common.response.StatusCode;
import club.emergency.wechat.common.utils.JsonConvert;
import club.emergency.wechat.exeception.provider.WechatException;
import club.emergency.wechat.model.wechat_api.*;
import club.emergency.wechat.redis.RedisOperation;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Create with IntelliJ IDEA
 * Project Name: wecaht
 * Package Name: club.emergency.wechat.wechat_api.provider.impl
 * Date: 2018/11/7
 *
 * @author: 快乐的小菌菌
 * Description:
 */
@Slf4j
@RestController
public class WechatApiImpl implements WechatApi {

    @Value("${wechat.appId}")
    private String appId;

    @Value("${wechat.secret}")
    private String secret;

    private RedisOperation<AccessToken> redisOperation;

    public WechatApiImpl(RedisOperation<AccessToken> redisOperation) {
        this.redisOperation = redisOperation;
    }

    @Override
    public String getOpenIdByCode(@RequestParam("code") String code) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        String format = String.format(url, appId, secret, code);
        CodeResult codeResult;
        String result = null;
        try {
            result = IOUtils.toString(new URL(format), StandardCharsets.UTF_8);
            codeResult = new JsonConvert<CodeResult>().underscoresToCamelDecode(result, CodeResult.class);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.ok(StatusCode.REDIS_GET_ERROR, "根据code获取openId获取失败，返回内容：" + result);
        }
        return ResponseEntity.ok(StatusCode.REDIS_GET_OK, "根据code获取openId获取成功", codeResult);
    }

    @Override
    public String uploadImageReturnUrl(@RequestParam("fileName") String fileName, @RequestBody byte[] bytes) {
        AccessToken accessToken = doGetAccessToken();
        String uploadImageUrl = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=%s";
        String url = String.format(uploadImageUrl, accessToken.getAccessToken());
        String result = new HttpsPostRequestUtil().doMultipartRequest(url, fileName, bytes);
        UploadResult uploadResult;
        try {
            uploadResult = new JsonConvert<UploadResult>().underscoresToCamelDecode(result, UploadResult.class);
        } catch (IOException e) {
            throw new WechatException("上传图片返回url地址失败！返回内容：" + result);
        }
        return ResponseEntity.ok(StatusCode.REQUEST_WECHAT_OK, "上传图片返回url地址成功！", uploadResult);
    }

    @Override
    public String getUserOpenIdList() {
        return ResponseEntity.ok(StatusCode.REQUEST_WECHAT_OK, "获取关注的用户OpenId列表成功！", doGetUserOpenIdList());
    }

    @Override
    public String getUserInfoByOpenId(@RequestParam("openId") String openId) {
        String urlStr = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN";
        String formatUrlStr = String.format(urlStr, doGetAccessToken().getAccessToken(), openId);
        HttpsPostRequestUtil httpsPostRequestUtil = new HttpsPostRequestUtil();
        String result = httpsPostRequestUtil.doJsonRequest(formatUrlStr, openId);
        UserInfo userInfo;
        try {
            userInfo = new JsonConvert<UserInfo>().underscoresToCamelDecode(result, UserInfo.class);
        } catch (IOException e) {
            return ResponseEntity.error(StatusCode.REQUEST_WECHAT_ERROR, "根据OpenId获取人员详细信息失败！对象解析失败！返回内容：" + result, e);
        }
        return ResponseEntity.ok(StatusCode.REQUEST_WECHAT_OK, "根据OpenId获取人员详细信息成功！", userInfo);
    }

    @Override
    public List<UserInfo> getUserInfoList(@RequestBody UserInfoSimple userInfoSimple) {
        String urlStr = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=%s";
        String url = String.format(urlStr, doGetAccessToken().getAccessToken());
        HttpsPostRequestUtil httpsPostRequestUtil = new HttpsPostRequestUtil();
        String result = httpsPostRequestUtil.doJsonRequest(url, userInfoSimple);
        List<UserInfo> userInfoList = null;
        try {
            userInfoList = new JsonConvert<UserInfoList>().underscoresToCamelDecode(result, UserInfoList.class).getUserInfoList();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return userInfoList;
    }

    /**
     * 获取关注的用户OpenId列表
     *
     * @return 对象
     */
    private TotalUserOpenId doGetUserOpenIdList() {
        AccessToken accessToken = doGetAccessToken();
        String preview = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s&next_openid=";
        String urlStr = String.format(preview, accessToken.getAccessToken());
        String result = null;
        try {
            URL url = new URL(urlStr);
            result = IOUtils.toString(url, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
        }
        TotalUserOpenId totalUserOpenId = null;
        try {
            totalUserOpenId = new JsonConvert<TotalUserOpenId>().underscoresToCamelDecode(result, TotalUserOpenId.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return totalUserOpenId;
    }

    /**
     * 从wechat获取access_token
     */
    private AccessToken getAccessTokenFromWechat() {
        String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appId, secret);
        AccessToken accessToken = null;
        try {
            String obj = IOUtils.toString(new URL(url), StandardCharsets.UTF_8);
            try {
                accessToken = new JsonConvert<AccessToken>().underscoresToCamelDecode(obj, AccessToken.class);
            } catch (UnrecognizedPropertyException e) {
                throw new WechatException("获取access_token数据异常,请根据错误代码检查异常信息,返回json：" + obj);
            }
            redisOperation.add("accessToken", accessToken, 1, TimeUnit.HOURS);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return accessToken;
    }

    private AccessToken doGetAccessToken() {
        Boolean flag = redisOperation.hasKey("accessToken");
        AccessToken accessToken;
        if (Objects.isNull(flag) || !flag) {
            accessToken = getAccessTokenFromWechat();
        } else {
            accessToken = redisOperation.get("accessToken", AccessToken.class);
        }
        return accessToken;
    }
}
